/**
 ****************************************************************************************************
 * @file        lwip_demo
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-08-01
 * @brief       lwIP SOCKET TCPClient 实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 阿波罗 F429开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <lwip/sockets.h>
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/api.h"
#include "lwip/mem.h"
#include "usart.h"

#include "sys.h"


#define LWIP_SEND_DATA              0X80    /* 定义有数据发送 */
extern uint8_t g_lwip_send_flag;            /* 数据发送标志位 */

/* 设置远程IP地址 */
//#define DEST_IP_ADDR0               192
//#define DEST_IP_ADDR1               168
//#define DEST_IP_ADDR2                 1
//#define DEST_IP_ADDR3               167

/* 需要自己设置远程IP地址 */
#define IP_ADDR   "192.168.1.111"

#define LWIP_DEMO_RX_BUFSIZE         100                        /* 最大接收数据长度 */
#define LWIP_DEMO_PORT               8080                       /* 连接的本地端口号 */
#define LWIP_SEND_THREAD_PRIO       ( tskIDLE_PRIORITY + 3 )    /* 发送数据线程优先级 */
/* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE];

/* 发送数据内容 */
uint8_t g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 数据发送标志位 */
uint8_t g_lwip_send_flag;
int g_lwip_sock = -1;
int g_lwip_connect_state = 0;
static void lwip_send_thread(void *arg);

static QueueHandle_t g_display_queue;     /* 显示消息队列句柄 */

/**
 * @brief       发送数据线程
 * @param       无
 * @retval      无
 */
void lwip_data_send(void)
{
    sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO );
}

/**
 * @brief       lwip_demo实验入口
 * @param       无
 * @retval      无
 */
void lwip_client_demo(void)
{
    struct sockaddr_in atk_client_addr;
    err_t err;
    int recv_data_len;
    BaseType_t lwip_err;
    char *tbuf;

    g_display_queue = xQueueCreate(20, 200);      /* 创建消息Message_Queue,队列项长度是200长度 */

    lwip_data_send();                                           /* 创建发送数据线程 */

    while (1)
    {
sock_start:
        g_lwip_connect_state = 0;
        atk_client_addr.sin_family = AF_INET;                   /* 表示IPv4网络协议 */
        atk_client_addr.sin_port = htons(LWIP_DEMO_PORT);       /* 端口号 */
        atk_client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);   /* 远程IP地址 */

        g_lwip_sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
        memset(&(atk_client_addr.sin_zero), 0, sizeof(atk_client_addr.sin_zero));

        tbuf = mem_malloc(200); /* 申请内存 */
        sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT); /* 客户端端口号 */

        /* 连接远程IP地址 */
        err = lwip_connect(g_lwip_sock, (struct sockaddr *)&atk_client_addr, sizeof(struct sockaddr));

        if (err == -1)
        {
            usart_transmit("连接失败\r\n");
            g_lwip_sock = -1;
            closesocket(g_lwip_sock);
            mem_free(tbuf);
            vTaskDelay(10);
            goto sock_start;
        }

        usart_transmit("连接成功\r\n");
        g_lwip_connect_state = 1;

        while (1)
        {
            recv_data_len = lwip_recv(g_lwip_sock,g_lwip_demo_recvbuf,
                                 LWIP_DEMO_RX_BUFSIZE,0);
            if (recv_data_len <= 0 )
            {
                closesocket(g_lwip_sock);
                g_lwip_sock = -1;
                mem_free(tbuf);
                goto sock_start;
            }

            /* 接收的数据 */
            lwip_err = xQueueSend(g_display_queue, &g_lwip_demo_recvbuf, 0);

            if (lwip_err == errQUEUE_FULL)
            {
                usart_transmit("队列Key_Queue已满, 数据发送失败!\r\n");
            }

            vTaskDelay(10);
        }
    }
}

/**
 * @brief       发送数据线程函数
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void lwip_send_thread(void *pvParameters)
{
    pvParameters = pvParameters;

    err_t err;

    while (1)
    {
        while (1)
        {
            if(((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) && (g_lwip_connect_state == 1)) /* 有数据要发送 */
            {
                err = lwip_write(g_lwip_sock, g_lwip_demo_sendbuf, sizeof(g_lwip_demo_sendbuf));

                if (err < 0)
                {
                    break;
                }

                g_lwip_send_flag &= ~LWIP_SEND_DATA;
            }

            vTaskDelay(10);
        }

        closesocket(g_lwip_sock);
    }
}

/**
 * @brief       显示任务
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void display_task(void *pvParameters)
{
    pvParameters = pvParameters;
    uint8_t *buffer;

    while(1)
    {
        buffer = mem_malloc(200);

        if (g_display_queue != NULL)
        {
            memset(buffer, 0, 200);       /* 清除缓冲区 */

            if (xQueueReceive(g_display_queue, buffer, portMAX_DELAY))
            {
                usart_transmit("%s\n", buffer);
            }
        }

        mem_free(buffer);          /*释放内存 */

        vTaskDelay(5);
    }
}
